package main

import (
	"errors"
	"strconv"

	"gitee.com/bon-ami/eztools/v3"
	_ "github.com/go-sql-driver/mysql"
)

// uniq is valid only when add is true
func choosePairOrAdd(db *eztools.Dbs, add, uniq bool, tbl ...string) (
	res map[string]string, err error) {
	if tbl == nil {
		return
	}
	var id int
	res = make(map[string]string)
	for _, i := range tbl {
		if add {
			id, err = db.ChoosePairOrAdd(i, true, uniq)
		} else {
			id, err = db.ChoosePair(i, true)
		}
		if err != nil {
			return
		}
		if id == eztools.InvalidID {
			err = errors.New("Invalid ID")
			return
		}
		if id == 0 { //zero value not allowed
			eztools.LogPrint("NO default allowed for " + i)
			err = errors.New("Zero Value")
			return
		}
		res[i] = strconv.Itoa(id)
	}
	return
}

func addReqExec(db *eztools.Dbs, date, android, tool, ver string) error {
	_, err := db.AddWtParams(tblGoogle,
		[]string{fldTool, fldAndroid,
			fldVer, fldReq},
		[]string{tool, android, ver, date}, false)
	if err != nil {
		eztools.LogPrint("FAILED to add new item to table google!")
		return err
	} else {
		eztools.LogPrint("Item added to table google")
	}
	return nil
}

func modReq(db *eztools.Dbs, id string) {
	searched, err := db.Search(tblGoogle,
		fldId+"="+id,
		[]string{fldId, fldAndroid,
			fldTool, fldVer,
			fldReq, fldExp},
		"")
	if err != nil {
		eztools.LogErrPrint(err)
		return
	}
	if len(searched) != 1 {
		eztools.LogPrint("No single record found for ID " + id)
		return
	}
	switch eztools.PromptStr("What to do with ID " + id +
		", Android " +
		getStrFromID(db, tblAndroid, searched[0][1]) +
		", Tool " +
		getStrFromID(db, tblTool, searched[0][2]) +
		", Version " +
		getStrFromID(db, tblVer, searched[0][3]) +
		", Requirement " +
		searched[0][4] +
		", Expiry " +
		searched[0][5] + "? Delete, Modify, or Pass?") {
	case "D", "d":
		switch eztools.PromptStr("Delete ID " + id + "?") {
		case "Y", "y":
			if err = db.DeleteWtID(tblGoogle, id); err != nil {
				eztools.LogErr(err)
			}
		}
	case "M", "m":
		m, err := choosePairOrAdd(db, true, true,
			tblTool, tblAndroid, tblVer)
		if err != nil {
			eztools.LogErrPrint(err)
			return
		}
		req := eztools.GetDate("Requirement date=")
		exp := eztools.GetDate("Expiry date=")
		if err = db.UpdateWtParams(tblGoogle,
			fldId+"="+id,
			[]string{fldAndroid, fldTool,
				fldVer, fldReq, fldExp},
			[]string{m[tblAndroid], m[tblTool],
				m[tblVer], req, exp}, false, false); err != nil {
			eztools.LogErr(err)
		}
	}
}

//update existing, adding new
func upReqExec(db *eztools.Dbs, date, android, tool string) error {
	//update existing, adding expiry
	cri := fldAndroid + "=" + android + " AND " +
		fldTool + "=" + tool + " AND " +
		fldExp + " IS NULL"
	searched, err := db.Search(tblGoogle, cri,
		[]string{fldId, fldReq},
		"")
	if err != nil {
		eztools.LogErrPrint(err)
		return err
	}
	switch len(searched) {
	case 0:
		eztools.ShowStrln("No former versions detected.")
	case 1:
		if eztools.TranDate(searched[0][1]) == date {
			eztools.ShowStrln("Same existing item found.")
			return nil
		} else {
			cri = fldId + "=" + searched[0][0]
			if err = db.UpdateWtParams(tblGoogle, cri,
				[]string{fldExp},
				[]string{date}, false, false); err != nil {
				eztools.LogErr(err)
			}
		}
	default:
		eztools.ShowStrln("TODO: multiple items with empty expiry")
	}
	return err
}

//update existing, adding new
func upNaddReq(db *eztools.Dbs, date, android, tool, ver string) error {
	if err := upReqExec(db, date, android, tool); err != nil {
		return err
	}
	return addReqExec(db, date, android, tool, ver)
}

//reuse the old one and update current one's expiry
func upNchgReq(db *eztools.Dbs, date, android, tool, id string) error {
	if err := upReqExec(db, date, android, tool); err != nil {
		return err
	}
	err := db.UpdateWtParams(tblGoogle,
		fldId+"="+id,
		[]string{fldReq}, []string{date}, false, false)
	if err != nil {
		eztools.LogErrPrint(err)
		return err
	}
	return nil
}

func upReq(db *eztools.Dbs, ch chan string, readonly bool) {
	var info string
	eztools.ShowStrln("Current google regulations.")
	for info = <-ch; len(info) > 0; info = <-ch {
		eztools.ShowStrln(info)
	}
	if readonly {
		return
	}
	date := eztools.GetDate("Enter the must-use date. (Invalid to modify existing.)")
	modify := false
	if date == "NULL" {
		/*switch eztools.PromptStr("NO date provided. Y/y to modify existing items. ") {
		case "Y", "y":
			modify(db)
		default:
			return
		}*/
		modify = true
	}
	for {
		m, err := choosePairOrAdd(db, !modify, true,
			tblTool, tblAndroid, tblVer)
		if err != nil {
			eztools.LogErrPrint(err)
			return
		}
		//selStrArr := []string{fldAndroid, fldTool, fldVer}
		//selStr := selStrArr[:]
		selStr := []string{fldAndroid, fldTool,
			fldVer, fldId}
		cri := fldTool + "=" + m[tblTool] + " AND " +
			fldVer + "=" + m[tblVer]
		updateAll := true
		if m[tblAndroid] != strconv.Itoa(eztools.AllID) {
			cri += " AND " + fldAndroid + "=" +
				m[tblAndroid]
			updateAll = false
		}
		//list exact tool and version (and android, if specified) in existence
		searched, err := db.Search(tblGoogle,
			cri, selStr, "")
		if err != nil {
			eztools.LogErrPrint(err)
			return
		}
		if len(searched) > 0 {
			eztools.ShowStrln(strconv.Itoa(len(searched)) +
				" results found. No new items will be added.")
			//update all in existence without adding any new
			for _, i := range searched {
				if eztools.Debugging {
					eztools.ShowStrln("changing " +
						getStrFromID(db,
							tblAndroid,
							i[0]))
				}
				switch modify {
				case false:
					if upNchgReq(db, date,
						m[tblAndroid],
						m[tblTool],
						i[3]) != nil {
						return
					}
				case true:
					modReq(db, i[3])
				}
			}
		} else if !modify {
			if updateAll {
				if eztools.Debugging {
					eztools.ShowStrln("adding for all...")
				}
				selStr[0] = fldId
				selStr = selStr[:1]
				searched, err = db.Search(
					tblAndroid, "", selStr, "")
				if err != nil {
					eztools.LogErrPrint(err)
					return
				}
				for _, i := range searched {
					if upNaddReq(db, date, i[0],
						m[tblTool],
						m[fldVer]) != nil {
						return
					}
				}
			} else if upNaddReq(db, date, m[tblAndroid],
				m[tblTool],
				m[fldVer]) != nil {
				return
			}
		} else {
			eztools.ShowStrln("No such items found")
		}
	}
}
